package com.gnkexy.springframework.beans.factory.support;

import com.gnkexy.springframework.beans.BeansException;
import com.gnkexy.springframework.beans.factory.ConfigurableListableBeanFactory;
import com.gnkexy.springframework.beans.factory.DisposableBean;
import com.gnkexy.springframework.beans.factory.config.BeanDefinition;
import com.gnkexy.springframework.beans.factory.config.BeanPostProcessor;
import com.gnkexy.springframework.context.supper.ApplicationContextAwareProcessor;

import java.lang.reflect.Type;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ConfigurableListableBeanFactory {

    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    private Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>();


    //比较map中是否存在beanName
    public boolean containsBeanDefinition(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        return beanDefinition != null ? true : false;
    }

    //注册beanDifinition对象到beanDefinitionMap中
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
        Class aClass = beanDefinition.getBeanClass();
        Set<Class<?>> classes = allBeanNamesByType.keySet();
        for (Class<?> c : classes) {
            if (c.isAssignableFrom(aClass)) {
                String[] strings = allBeanNamesByType.get(c);
                ArrayList<String> list = new ArrayList<>();
                for (String string : strings) {
                    list.add(string);
                }
                list.add(beanName);
                String[] array = list.toArray(new String[0]);
                allBeanNamesByType.put(aClass, array);
                return;
            }
        }
        allBeanNamesByType.put(aClass, new String[]{beanName});
    }

    //获取BeanDefinition对象
    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
        return beanDefinition;
    }

    //将所有的单例的BeanDefinition对象实例化，放到单例池中
    @Override
    public void preInstantiateSingletons() throws BeansException {
        for (String s : beanDefinitionMap.keySet()) {
//            getBean(s);
            doGetBean(s, new Object[0]);
        }
    }


    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
//        List<String> list = new ArrayList<>();
//        Set<Map.Entry<String, BeanDefinition>> entries = beanDefinitionMap.entrySet();
//        for (Map.Entry<String, BeanDefinition> entry : entries) {
//            String name = entry.getValue().getBeanClass().getName();
//            String[] split = type.getName().split("\\.");
//            String[] split1 = name.split("\\.");
//            String s = split[split.length - 1];
//            String s1 = split1[split1.length - 1];
//            if (s1.contains(s)) {
//                list.add(entry.getKey());
//            }
//        }
//        Map<String, T> map = new HashMap<>();
//        for (String s : list) {
//            Object bean = getBean(s);
//            map.put(s, (T) bean);
//        }
//        return map;
        HashMap<String, T> map = new HashMap<>();

        for (Class<?> aClass : allBeanNamesByType.keySet()) {
            if(type.isAssignableFrom(aClass)){
                String[] strings = allBeanNamesByType.get(aClass);
                for (String string : strings) {
                    Object o = doGetBean(string, new Object[0]);
                    map.put(string, (T) o);
                }
            }
        }
        return map;
    }

    @Override
    public Object getBeanDifinitionNames() {
        return null;
    }


    public void destroySingletons() {
        Collection<DisposableBean> values = getDisposableBeans().values();
        for (DisposableBean value : values) {
            value.destroy();
        }
    }

    //    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        String name = beanPostProcessor.getClass().getName();
        addSingleton(name, beanPostProcessor);
    }

    @Override
    public void registerSingleton(String name, Object bean) {
        addSingleton(name, bean);
    }
}
